package com.sdhs.paas.internet.util.regex;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class PathNameWildcardCompiler
{
  public static final int FORCE_ABSOLUTE_PATH = 4096;
  public static final int FORCE_RELATIVE_PATH = 8192;
  public static final int FORCE_MATCH_PREFIX = 16384;
  private static final char ESCAPE_CHAR = '\\';
  private static final char SLASH = '/';
  private static final char UNDERSCORE = '_';
  private static final char DASH = '-';
  private static final char DOT = '.';
  private static final char STAR = '*';
  private static final char QUESTION = '?';
  private static final String REGEX_MATCH_PREFIX = "^";
  private static final String REGEX_WORD_BOUNDARY = "\\b";
  private static final String REGEX_SLASH = "\\/";
  private static final String REGEX_SLASH_NO_DUP = "\\/(?!\\/)";
  private static final String REGEX_FILE_NAME_CHAR = "[\\w\\-\\.]";
  private static final String REGEX_FILE_NAME_SINGLE_CHAR = "([\\w\\-\\.])";
  private static final String REGEX_FILE_NAME = "([\\w\\-\\.]*)";
  private static final String REGEX_FILE_PATH = "([\\w\\-\\.]+(?:\\/(?!\\/)[\\w\\-\\.]*)*(?=\\/|$)|)\\/?";
  private static final int LAST_TOKEN_START = 0;
  private static final int LAST_TOKEN_SLASH = 1;
  private static final int LAST_TOKEN_FILE_NAME = 2;
  private static final int LAST_TOKEN_STAR = 3;
  private static final int LAST_TOKEN_DOUBLE_STAR = 4;
  private static final int LAST_TOKEN_QUESTION = 5;

  public static Pattern compilePathName(String pattern)
    throws PatternSyntaxException
  {
    return compilePathName(pattern, 0);
  }

  public static Pattern compilePathName(String pattern, int options)
    throws PatternSyntaxException
  {
    return Pattern.compile(pathNameToRegex(pattern, options), options);
  }

  public static int getPathNameRelevancy(String pattern)
  {
    pattern = normalizePathName(pattern);

    if (pattern == null) {
      return 0;
    }

    int relevant = 0;

    for (int i = 0; i < pattern.length(); i++) {
      switch (pattern.charAt(i)) {
      case '*':
      case '/':
      case '?':
        break;
      default:
        relevant++;
      }
    }

    return relevant;
  }

  public static String pathNameToRegex(String pattern, int options)
    throws PatternSyntaxException
  {
    pattern = normalizePathName(pattern);

    int lastToken = 0;
    StringBuilder buf = new StringBuilder(pattern.length() * 2);

    boolean forceMatchPrefix = (options & 0x4000) != 0;
    boolean forceAbsolutePath = (options & 0x1000) != 0;
    boolean forceRelativePath = (options & 0x2000) != 0;

    if (((forceMatchPrefix) && 
      (!pattern.startsWith("*")) && (!pattern.startsWith("/")) && 
      (!pattern
      .startsWith("?"))) || (
      (pattern.length() > 0) && 
      (pattern.charAt(0) == '/'))) {
      buf.append("^");
    }

    if ((pattern.length() == 1) && (pattern.charAt(0) == '/')) {
      pattern = "";
    }

    for (int i = 0; i < pattern.length(); i++) {
      char ch = pattern.charAt(i);

      if ((forceAbsolutePath) && (lastToken == 0) && (ch != '/')) {
        throw new PatternSyntaxException("Syntax Error", pattern, i);
      }

      switch (ch)
      {
      case '/':
        if (lastToken == 1)
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        if ((forceRelativePath) && (lastToken == 0)) {
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        }

        if (lastToken != 4) {
          buf.append("\\/(?!\\/)");
        }

        lastToken = 1;
        break;
      case '*':
        int j = i + 1;

        if ((j < pattern.length()) && (pattern.charAt(j) == '*')) {
          i = j;

          if ((lastToken != 0) && (lastToken != 1)) {
            throw new PatternSyntaxException("Syntax Error", pattern, i);
          }

          lastToken = 4;
          buf.append("([\\w\\-\\.]+(?:\\/(?!\\/)[\\w\\-\\.]*)*(?=\\/|$)|)\\/?");
        }
        else {
          if ((lastToken == 3) || (lastToken == 4)) {
            throw new PatternSyntaxException("Syntax Error", pattern, i);
          }

          lastToken = 3;
          buf.append("([\\w\\-\\.]*)");
        }

        break;
      case '?':
        lastToken = 5;
        buf.append("([\\w\\-\\.])");
        break;
      default:
        if (lastToken == 4) {
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        }

        if ((Character.isLetterOrDigit(ch)) || (ch == '_') || (ch == '-'))
        {
          if ((lastToken == 0) && ((!forceMatchPrefix) || (i != 0)))
            buf.append("\\b").append(ch);
          else if (i + 1 == pattern.length())
            buf.append(ch).append("\\b");
          else
            buf.append(ch);
        }
        else if (ch == '.')
          buf.append('\\').append('.');
        else {
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        }

        lastToken = 2;
      }
    }

    return buf.toString();
  }

  public static String normalizePathName(String name)
  {
    if (name == null) {
      return null;
    }

    return name.trim().replaceAll("[/\\\\]+", "/");
  }
}